; constantes globales
	%include "constantes.mac"

; parametros
	%define rgb					[ebp + 8]
	%define modulo4				0x00000003
	%define modulo512			0x000001FF
	%define bytes_reservados	32
	%define cuatro_pixeles 		12

; variables locales
	%define p_fila 				[ebp - 16]
	%define p_columna 			[ebp - 20]
	%define p_pantalla		 	[ebp - 24]

	%define var_x		 		[ebp - 28]
	%define index_1			 	[ebp - 32]	; 128 + (x >> 4)
	%define index_2			 	[ebp - 36]	; index << 2 + 1
	%define index_3			 	[ebp - 40]	; 255 - (index << 2 + 1)

	%define ancho_fondo_bytes 	[ebp - 44]

	extern screen_pixeles	;extern Uint8 *screen_pixeles
	extern colores			;extern int colores[]

	extern g_ver0			;extern Uint16 g_ver0
	extern g_ver1			;extern Uint16 g_ver1
	extern g_hor0			;extern Uint16 g_hor0
	extern g_hor1			;extern Uint16 g_hor1

global generarPlasma

section .rodata

	mask_ones:	dd 0xFFFFFFFF, 0xFFFFFFFF, 0x0, 0x0
	mask_deny:	dd 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF

	mask_255_G:	db 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
				db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

	mask_r:		db 0x00, 0xFF, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF,
				db 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
	
	mask_g:		db 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x04, 0xFF, 0xFF,
				db 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF

	cmp_0:		dw  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1
	cmp_64: 	dw  63,  63,  63,  63,  63,  63,  63,  63
	cmp_128: 	dw 127, 127, 127, 127, 127, 127, 127, 127
	cmp_192: 	dw 191, 191, 191, 191, 191, 191, 191, 191
	cmp_256: 	dw 255, 255, 255, 255, 255, 255, 255, 255

	mask_copy:	db 0x0, 0x1, 0x0, 0x1, 0x4, 0x5, 0x4, 0x5,
				db 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0

	mask_G2R:	db 0x01, 0xFF, 0xFF, 0xFF, 0x05, 0xFF, 0xFF, 0xFF,
				db 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF

	mask_R2G:	db 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x04, 0xFF, 0xFF,
				db 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF

	mask_copy_R2G:	db 0x00, 0x00, 0xFF, 0xFF, 0x04, 0x04, 0xFF, 0xFF,
					db 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF

	;DESDE: 0G0R0b0g-0r0B0G0R | HASTA: 00000000-0bgr0BGR
	mask_pxl_0:	db 0x00, 0x02, 0x04, 0xFF, 0x06, 0x08, 0x0A, 0xFF,
				db 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF

	;DESDE: 00000000-0bgr0BGR | HASTA: 00000000-00bgrBGR
	mask_pxl_1:	db 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0xFF, 0xFF,
				db 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF

	;DESDE: 00000000-0bgr0BGR | HASTA: 0000bgrB-GR000000
	mask_pxl_2:	db 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01,
				db 0x02, 0x04, 0x05, 0x06, 0xFF, 0xFF, 0xFF, 0xFF

	;DESDE: 00000000-00000OFF | HASTA: 00000000-0OFF0OFF
	color_off:	db 0x00, 0x01, 0x02, 0xFF, 0x00, 0x01, 0x02, 0xFF,
				db 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF

    mask_8_bit: dw 0x00FF, 0x00FF, 0x00FF, 0x00FF,
			    dw 0x00FF, 0x00FF, 0x00FF, 0x00FF

section .text

generarPlasma:

	push ebp		; creo el marco de la pila
	mov ebp, esp	; creo el marco de la pila

	push ebx		; salvo registros convencion C
	push edi		; salvo registros convencion C
	push esi		; salvo registros convencion C

	sub esp, bytes_reservados	; reservo memoria en la pila

calculoAnchoFondoBytes:

	mov eax, ancho_pantalla
	mov ebx, bytes_por_pixel
	mul ebx
	mov dword ancho_fondo_bytes, eax

inicializarVariables:

	mov dword p_fila, 0				; p_fila = 0
	mov eax, [screen_pixeles]		; p_pantalla = screen_pixels
	mov p_pantalla, eax				; p_pantalla = screen_pixels
	xor esi, esi					; esi = contador de fila = 0

paraCadaFila:

	cmp esi, alto_pantalla		; esi = alto_pantalla ? termino
	je fin						; esi = alto_pantalla ? termino
	mov eax, p_fila
	mov p_columna, eax			; p_columna = p_fila

	xor edi, edi				; edi = contador de columna = 0

paraCadaColumna:

	cmp edi, ancho_pantalla		; edi = ancho_pantalla ? cambio de fila
	je siguienteFila			; edi = ancho_pantalla ? cambio de fila

calculoColor:

	mov dword var_x, 0			; inicializo var_x	

	;colores[(g_ver0 + 5 * columna) % 512]
	mov eax, 5
	mul edi
	mov ebx, eax
	add ebx, dword [g_ver0]
	and ebx, modulo512
	mov eax, [colores + ebx * 4]
	add dword var_x, eax

	;colores[(g_ver1 + 3 * columna) % 512]
	mov eax, 3
	mul edi
	mov ebx, eax
	add ebx, dword [g_ver1]
	and ebx, modulo512
	mov eax, [colores + ebx * 4]
	add dword var_x, eax

	;colores[(g_hor0 + 3 * fila) % 512]
	mov eax, 3
	mul esi
	mov ebx, eax
	add ebx, dword [g_hor0]
	and ebx, modulo512
	mov eax, [colores + ebx * 4]
	add dword var_x, eax

	;colores[(g_hor1 + fila) % 512]
	mov ebx, dword [g_hor1]
	add ebx, esi
	and ebx, modulo512
	mov eax, [colores + ebx * 4]
	add dword var_x, eax

	;index_1 = 128 + (x >> 4)
	mov edx, var_x
	shr edx, 4
	mov dword index_1, edx
	add dword index_1, 128

	;index_2 = index << 2 + 1
	mov edx, index_1
	shl edx, 2
	inc edx
	mov dword index_2, edx

	;index_3 = 255 - (index << 2 + 1)
	mov edx, index_2
	mov dword index_3, 255
	sub dword index_3, edx

	mov eax, edi
	and eax, modulo4

repartoColor:

	cmp eax, 0
	je primerColor
	cmp eax, 1
	je segundoColor
	cmp eax, 2
	je tercerColor
	cmp eax, 3
	je cuartoColor

primerColor:

	movd mm0, index_1
	movd mm2, index_2
	movd mm4, index_3
	jmp muevoPunteros

segundoColor:

	movd mm7, index_1
	psllq mm7, 32
	por mm0, mm7

	movd mm7, index_2
	psllq mm7, 32
	por mm2, mm7

	movd mm7, index_3
	psllq mm7, 32
	por mm4, mm7

	jmp muevoPunteros

tercerColor:

	movd mm1, index_1
	movd mm3, index_2
	movd mm5, index_3
	jmp muevoPunteros

cuartoColor:

	movd mm7, index_1
	psllq mm7, 32
	por mm1, mm7

	movd mm7, index_2
	psllq mm7, 32
	por mm3, mm7

	movd mm7, index_3
	psllq mm7, 32
	por mm5, mm7

creaVariables:

	pshufb mm0, [mask_copy]
	pshufb mm2, [mask_g]
	pshufb mm4, [mask_r]
	por mm4, mm2

	pshufb mm2, [mask_G2R]
	por mm2, [mask_255_G]

	pshufb mm1, [mask_copy]
	pshufb mm3, [mask_g]
	pshufb mm5, [mask_r]
	por mm5, mm3

	pshufb mm3, [mask_G2R]
	por mm3, [mask_255_G]

empiezaSSE:

	movd xmm7, rgb				; xmm7 = color_off
	pshufb xmm7, [color_off]	; xmm7 = color_off

	mov eax, p_pantalla
	sub eax, cuatro_pixeles
	movdqu xmm0, [eax]			; se levantan 5 pixeles y un byte
	movdqu xmm1, xmm0			; xmm1 = xmm0

	pxor xmm3, xmm3				; limpio xmm3
	punpcklbw xmm1, xmm3		; se desempaquetan 2 primeros pixeles

	pxor xmm3, xmm3				; limpio xmm3
	psrldq xmm0, 6				; 0000-00rB-GRbg-rBGR
	movdqu xmm2, xmm0			; xmm2 = xmm0
	punpcklbw xmm2, xmm3		; se desempaquetan 2 segundos pixeles

	psrldq xmm0, 6				; 0000-0000-0000-rBGR
	pslldq xmm0, 12				; rBGR-0000-0000-0000

acomodoPixelesBaja: ;(puedo usar xmm4 y xmm6)

	movq2dq xmm6, mm1
	pxor mm1, mm1
    pand mm0, [mask_8_bit]

	;index < 64
	movq mm6, mm0
	movq mm7, mm0
	pcmpgtd mm6, [cmp_0]
	pcmpgtd mm7, [cmp_64]
	pxor mm7, [mask_deny]
	pand mm6, mm7
	pand mm6, mm4
	por mm1, mm6

	;64 <= index < 128
	movq mm6, mm0
	movq mm7, mm0
	pcmpgtd mm6, [cmp_64]
	pcmpgtd mm7, [cmp_128]
	pxor mm7, [mask_deny]
	pand mm6, mm7
	pand mm6, mm2
	por mm1, mm6

	;128 <= index < 192
	movq mm6, mm0
	movq mm7, mm0
	pcmpgtd mm6, [cmp_128]
	pcmpgtd mm7, [cmp_192]
	pxor mm7, [mask_deny]
	pand mm6, mm7
	pand mm6, mm4
	pshufb mm6, [mask_copy_R2G]
	por mm1, mm6

	;192 <= index < 256
	movq mm6, mm0
	movq mm7, mm0
	pcmpgtd mm6, [cmp_192]
	pcmpgtd mm7, [cmp_256]
	pxor mm7, [mask_deny]
	pand mm6, mm7
	pand mm6, mm2
	pshufb mm6, [mask_r]
	por mm1, mm6

	movq2dq xmm4, mm1
	movdq2q mm1, xmm6

	pshufb xmm1, [mask_pxl_0]	; acomodo los pixeles (00000000-0bgr0BGR)
	movdqu xmm3, xmm1			; xmm3 = copia de xmm1
	pcmpeqd xmm3, xmm7			; xmm3 == color_off ?
	pand xmm3, xmm4				; xmm3 = pixeles plasma

	movdqu xmm5, xmm1			; xmm5 = otra copia de xmm1
	pcmpeqd xmm5, xmm7			; xmm5 == color_off ?
	pxor xmm5, [mask_ones]		; invierto mascara en xmm5
	pand xmm5, xmm1				; xmm5 = pixeles NO color_off

	movdqu xmm1, xmm3			; xmm1 = xmm3 + xmm5
	paddq xmm1, xmm5			; xmm1 = xmm3 + xmm5
	pshufb xmm1, [mask_pxl_1]	; xmm1 = 0000-0000-00bg-rBGR

acomodoPixelesAlta: ;(puedo usar xmm3 y xmm5)

	movq2dq xmm5, mm0
	pxor mm0, mm0
    pand mm1, [mask_8_bit]

	;index < 64
	movq mm6, mm1
	movq mm7, mm1
	pcmpgtd mm6, [cmp_0]
	pcmpgtd mm7, [cmp_64]
	pxor mm7, [mask_deny]
	pand mm6, mm7
	pand mm6, mm5
	por mm0, mm6

	;64 <= index < 128
	movq mm6, mm1
	movq mm7, mm1
	pcmpgtd mm6, [cmp_64]
	pcmpgtd mm7, [cmp_128]
	pxor mm7, [mask_deny]
	pand mm6, mm7
	pand mm6, mm3
	por mm0, mm6

	;128 <= index < 192
	movq mm6, mm1
	movq mm7, mm1
	pcmpgtd mm6, [cmp_128]
	pcmpgtd mm7, [cmp_192]
	pxor mm7, [mask_deny]
	pand mm6, mm7
	pand mm6, mm5
	pshufb mm6, [mask_copy_R2G]
	por mm0, mm6

	;192 <= index < 256
	movq mm6, mm1
	movq mm7, mm1
	pcmpgtd mm6, [cmp_192]
	pcmpgtd mm7, [cmp_256]
	pxor mm7, [mask_deny]
	pand mm6, mm7
	pand mm6, mm3
	pshufb mm6, [mask_r]
	por mm0, mm6

	movq2dq xmm3, mm0
	movdq2q mm0, xmm5

	pshufb xmm2, [mask_pxl_0]	; acomodo los pixeles (00000000-0bgr0BGR)
	movdqu xmm4, xmm2			; xmm4 = copia de xmm2
	pcmpeqd xmm4, xmm7			; xmm4 == color_off ?
	pand xmm4, xmm3				; xmm4 = pixeles plasma

	movdqu xmm6, xmm2			; xmm6 = otra copia de xmm2
	pcmpeqd xmm6, xmm7			; xmm6 == color_off ?
	pxor xmm6, [mask_ones]		; invierto mascara en xmm6
	pand xmm6, xmm2				; xmm6 = pixeles NO color_off

	movdqu xmm2, xmm4			; xmm2 = xmm4 + xmm6
	paddq xmm2, xmm6			; xmm2 = xmm4 + xmm6
	pshufb xmm2, [mask_pxl_2]	; xmm2 = 0000-bgrB-GR00-0000

juntoPixeles:

	por xmm0, xmm1				; xmm1 = rBGR-0000-00bg-rBGR
	por xmm0, xmm2				; xmm1 = rBGR-bgrB-GRbg-rBGR
	mov eax, p_pantalla
	sub eax, cuatro_pixeles
	movdqu [eax], xmm0			; devuelvo a pantalla los 128 bits

muevoPunteros:

	mov eax, p_pantalla			; avanzo puntero pantalla un pixel
	add eax, bytes_por_pixel	; avanzo puntero pantalla un pixel
	mov p_pantalla, eax			; avanzo puntero pantalla un pixel

	mov eax, p_columna			; avanzo puntero columna un pixel
	add eax, bytes_por_pixel	; avanzo puntero columna un pixel
	mov p_columna, eax			; avanzo puntero columna un pixel

siguienteColumna:

	inc edi
	jmp paraCadaColumna

siguienteFila:

	inc esi
	mov eax, ancho_fondo_bytes
	add p_fila, eax

	jmp paraCadaFila

fin:

	add dword [g_ver0], 9
	add dword [g_hor0], 8

	add esp, bytes_reservados	; desarmo el stack frame

	pop esi						; desarmo el stack frame
	pop edi						; desarmo el stack frame
	pop ebx						; desarmo el stack frame
	pop ebp						; desarmo el stack frame

	ret
